package model

import (
	"encoding/json"
	"errors"
	"fmt"

	"gddgame.cc/galaxy/common/dsl/game"
	"gddgame.cc/galaxy/common/dsl/game/ad"
	"gddgame.cc/galaxy/common/dsl/game/config"
	"gddgame.cc/galaxy/common/dsl/game/language"
	"gddgame.cc/galaxy/common/dsl/game/reward"
	"gddgame.cc/galaxy/common/dsl/game/sync"
	"gddgame.cc/galaxy/common/dsl/game/user"
	"gddgame.cc/galaxy/common/namespaces/cooperate"
	"gddgame.cc/galaxy/common/namespaces/cooperate/structure"
	"gddgame.cc/galaxy/utils"
)

//go:generate msgp

//msgp DataRelationType
type DataRelationType string

func (t DataRelationType) Generate(key string) string {
	// 写死的规则，在Env->provider中
	switch t {
	case UserType:
		fallthrough
	case AllianceType:
		fallthrough
	case BuildType:
		fallthrough
	case UnitType:
		return "relationGroup:" + key + "/name"
	}
	return string(t) + ":" + key + "/name"
}

const (
	UserType     DataRelationType = "user"     // 条件，消耗，获取
	AllianceType DataRelationType = "alliance" // 条件，消耗，获取
	BuildType    DataRelationType = "build"    // 条件，消耗，获取
	UnitType     DataRelationType = "unit"     // 条件，消耗，获取

	AttrType   DataRelationType = "attr"   // 效果
	BuffType   DataRelationType = "buff"   // 效果
	SkillType  DataRelationType = "skill"  // 效果
	DirectType DataRelationType = "direct" // 效果

	PowerType   DataRelationType = "power"   // 条件
	ScienceType DataRelationType = "science" // 条件
	PropType    DataRelationType = "prop"    // 条件，消耗，获取
	EquipType   DataRelationType = "equip"   //消耗，获取
)

const (
	DefineAiMode          string = "aiMode"
	DefineBehaviorPattern string = "behaviorPattern"
)
const (
	UnitInFree   int = iota
	UnitInBattle int = 1
	UnitInTrain  int = 2
)

const (
	DirectAbilityDefine cooperate.AbilityDefine = "direct"
	AttrAbilityDefine   cooperate.AbilityDefine = "attr"
	BuffAbilityDefine   cooperate.AbilityDefine = "buff"
)
const (
	ScienceAbilitySource cooperate.AbilitySource = "science"
	PowerAbilitySource   cooperate.AbilitySource = "power"
	EquipAbilitySource   cooperate.AbilitySource = "equip"
	PropAbilitySource    cooperate.AbilitySource = "prop"
	LevelAbilitySource   cooperate.AbilitySource = "level"
)

//msgp DirectMode
type DirectMode byte

const (
	// 手动技能
	MainDirectMode DirectMode = iota
	AutoDirectMode
	ManualDirectMode
	BuildDirectMode
	PlaceDirectMode
	BuffDirectMode
	GroupBuffDirectMode
)

type TargetMode byte

const (
	_ TargetMode = iota
	SingleTargetMode
	SelfTargetMode
	RangeTargetMode
)

//msgp OperationType
type OperationType byte

const (
	BaseOperationType OperationType = iota
	DirectOperationType
)

//msgp UnitOperationType
type UnitOperationType byte

const (
	NoneUnitOperationType UnitOperationType = iota
	MultiUnitOperationType
	SelfUnitOperationType
)

//msgp OperationShow
type OperationShow byte

const (
	_                           OperationShow = iota
	SelfOperationShow                         = 1 << 0
	FriendOperationShow                       = 1 << 1
	AllianceOperationShow                     = 1 << 2
	FriendAllianceOperationShow               = 1 << 3
	EnemyOperationShow                        = 1 << 4
	NeutralOperationShow                      = 1 << 5
)

//msgp PropMode
type PropMode byte

const (
	UseSelfPropMode PropMode = iota
	PutUnitPropMode
	DirectPropMode
	CurrencyPropMode
)

//msgp:tuple DataRelation
type DataRelation struct {
	Type  DataRelationType `json:"type" msg:"type"`
	Key   interface{}      `json:"key" msg:"key"`
	Value int              `json:"value" msg:"value"`

	Reach   string `json:"reach" msg:"reach"`
	UnReach string `json:"unreach" msg:"unreach"`
	Text    string `json:"text" msg:"text"`
}

//msgp:tuple DataSliceRelation
type DataSliceRelation struct {
	Type  DataRelationType `json:"type" msg:"type"`
	Key   interface{}      `json:"key" msg:"key"`
	Value []int            `json:"value" msg:"value"`
}

//msgp:tuple CompareDataRelation
type CompareDataRelation struct {
	Type    DataRelationType `json:"type" msg:"type"`
	Key     interface{}      `json:"key" msg:"key"`
	Value   int              `json:"value" msg:"value"`
	Compare byte             `json:"compare" msg:"compare"`

	Reach   string `json:"reach" msg:"reach"`
	UnReach string `json:"unreach" msg:"unreach"`
	Text    string `json:"text" msg:"text"`
}

//msgp:tuple CompareGroupRelation
type CompareGroupRelation struct {
	Id      int  `json:"id" msg:"id"`
	Compare byte `json:"compare" msg:"compare"`
}

func (relation *CompareGroupRelation) Comp(source int, target int) bool {
	c := &CompareInfo{Value: target, Compare: relation.Compare}
	return c.Valid(source)
}

//msgp:tuple RelationSelect
type RelationSelect struct {
	Level    bool   `json:"level" msg:"level"`
	Relation string `json:"relation" msg:"relation"`
}

//msgp:tuple TargetSelect
type TargetSelect struct {
	Type structure.PublicDataType `json:"type" msg:"type"`
	Ids  []int                    `json:"ids" msg:"ids"`
}

//msgp:tuple TargetDataRelation
type TargetDataRelation struct {
	Relation TargetSelect      `json:"relation" msg:"relation"`
	List     DataRelationSlice `json:"list" msg:"list"`
}

//msgp TargetDataRelationSlice
type TargetDataRelationSlice []TargetDataRelation

func (slice TargetDataRelationSlice) Effect() map[structure.PublicDataType]map[int]*Effect {
	m := make(map[structure.PublicDataType]map[int]*Effect, len(slice))
	for index := range slice {
		effect := slice[index].List.Effect()
		pm, ok := m[slice[index].Relation.Type]
		if !ok {
			pm = map[int]*Effect{}
			m[slice[index].Relation.Type] = pm
		}
		for _, id := range slice[index].Relation.Ids {
			pm[id] = effect
		}
	}
	return m
}

//msgp DataRelationSlice
type DataRelationSlice []DataRelation

//msgp DataSliceRelationSlice
type DataSliceRelationSlice []DataSliceRelation

//msgp CompareDataRelationSlice
type CompareDataRelationSlice []CompareDataRelation

func (slice DataRelationSlice) Show() []DataRelationShow {
	list := make([]DataRelationShow, len(slice))
	for index, item := range slice {
		list[index] = DataRelationShow{
			Type:        item.Type,
			Key:         utils.ToString(item.Key),
			Value:       item.Value,
			LanguageKey: item.Type.Generate(utils.ToString(item.Key)),
		}
	}
	return list
}

func (slice DataRelationSlice) ReachShow() []DataRelationReachShow {
	list := make([]DataRelationReachShow, len(slice))
	for index, item := range slice {
		list[index] = DataRelationReachShow{
			Type:        item.Type,
			Key:         utils.ToString(item.Key),
			Value:       item.Value,
			LanguageKey: item.Type.Generate(utils.ToString(item.Key)),

			Reach:       item.Reach,
			UnReach:     item.UnReach,
			UnReachText: item.Text,
		}
	}
	return list
}
func (slice DataRelationSlice) TextShow() []DataRelationTextShow {
	list := make([]DataRelationTextShow, len(slice))
	for index, item := range slice {
		list[index] = DataRelationTextShow{
			Type:        item.Type,
			Key:         utils.ToString(item.Key),
			Value:       item.Value,
			LanguageKey: item.Type.Generate(utils.ToString(item.Key)),
		}
	}
	return list
}

func (slice CompareDataRelationSlice) Show() []CompareDataRelationShow {
	list := make([]CompareDataRelationShow, len(slice))
	for index, item := range slice {
		list[index] = CompareDataRelationShow{
			Type:        item.Type,
			Key:         utils.ToString(item.Key),
			Value:       item.Value,
			Compare:     item.Compare,
			LanguageKey: item.Type.Generate(utils.ToString(item.Key)),
		}
	}
	return list
}
func (slice CompareDataRelationSlice) ReachShow() []CompareDataRelationReachShow {
	list := make([]CompareDataRelationReachShow, len(slice))
	for index, item := range slice {
		list[index] = CompareDataRelationReachShow{
			Type:        item.Type,
			Key:         utils.ToString(item.Key),
			Value:       item.Value,
			Compare:     item.Compare,
			LanguageKey: item.Type.Generate(utils.ToString(item.Key)),

			Reach:       item.Reach,
			UnReach:     item.UnReach,
			UnReachText: item.Text,
		}
	}
	return list
}
func (slice CompareDataRelationSlice) TextShow() []CompareDataRelationTextShow {
	list := make([]CompareDataRelationTextShow, len(slice))
	for index, item := range slice {
		list[index] = CompareDataRelationTextShow{
			Type:        item.Type,
			Key:         utils.ToString(item.Key),
			Value:       item.Value,
			Compare:     item.Compare,
			LanguageKey: item.Type.Generate(utils.ToString(item.Key)),

			Text: item.Text,
		}
	}
	return list
}

func (slice CompareDataRelationSlice) Require() *Require {
	r := &Require{
		Sciences: map[int]CompareInfo{},
		Powers:   map[int]CompareInfo{},
		User:     map[int]CompareInfo{},
		Owner:    map[int]CompareInfo{},
	}
	for _, item := range slice {
		c := CompareInfo{Value: item.Value, Compare: item.Compare}
		switch item.Type {
		case ScienceType:
			r.Sciences[utils.ToInt(item.Key)] = c
		case PowerType:
			r.Powers[utils.ToInt(item.Key)] = c
		case UserType:
			r.User[utils.ToInt(item.Key)] = c
		case UnitType:
			fallthrough
		case BuildType:
			r.Owner[utils.ToInt(item.Key)] = c
		}
	}
	return r
}

func (slice DataRelationSlice) Consume() *Consume {
	c := &Consume{
		User:  map[int]int{},
		Props: map[int]int{},
		Owner: map[int]int{},
	}
	for _, item := range slice {
		switch item.Type {
		case UserType:
			c.User[utils.ToInt(item.Key)] = item.Value
		case PropType:
			c.Props[utils.ToInt(item.Key)] = item.Value
		case UnitType:
			fallthrough
		case BuildType:
			c.Owner[utils.ToInt(item.Key)] = item.Value
		}
	}
	return c
}

func (slice DataRelationSlice) Effect() *Effect {
	e := &Effect{
		DirectIds:   []int{},
		BuffIds:     []int{},
		Attrs:       game.IntAbilitySlice{},
		InlineAttrs: game.IntAbilityMap{},
	}

	for _, item := range slice {
		key := utils.ToInt(item.Key)
		if key == 0 {
			continue
		}
		switch item.Type {
		case DirectType:
			e.DirectIds = append(e.DirectIds, key)
		case BuffType:
			e.BuffIds = append(e.BuffIds, key)
		case AttrType:
			e.Attrs = append(e.Attrs, key, item.Value)
			e.InlineAttrs[key] = item.Value
		}
	}
	return e
}

func (slice DataRelationSlice) Receive() *Receive {
	r := &Receive{
		User:   map[int]int{},
		Props:  map[int]int{},
		Equips: map[int]int{},
	}
	for _, item := range slice {
		switch item.Type {
		case UserType:
			r.User[utils.ToInt(item.Key)] = item.Value
		case PropType:
			r.Props[utils.ToInt(item.Key)] = item.Value
		case EquipType:
			r.Equips[utils.ToInt(item.Key)] = item.Value
		}
	}
	return r
}

//
////msgp:tuple ShowAttr
//type ShowAttr struct {
//	Health         int `json:"health" msg:"health"`
//	Attack         int `json:"attack" msg:"attack"`
//	Defense        int `json:"defense" msg:"defense"`
//	AttackSpeed    int `json:"attack_speed" msg:"attack_speed"`
//	AttackDistance int `json:"attack_distance" msg:"attack_distance"`
//	Speed          int `json:"speed" msg:"speed"`
//	View           int `json:"view" msg:"view"`
//}
//
//func (showAttr ShowAttr) FromAttr(attr []attr.ObjectAttr, data *attr.AttrData) {
//	for _, objectAttr := range attr {
//		info := data.AttrMap[int(objectAttr.Index)]
//		switch info.Key {
//		case "allHealth":
//			showAttr.Health += objectAttr.Value
//		case "attack":
//			showAttr.Attack += objectAttr.Value
//		case "defense":
//			showAttr.Defense += objectAttr.Value
//		}
//	}
//}
//func (showAttr ShowAttr) FromData(dataRelation *DataRelation, data *attr.AttrData) {
//	info := data.AttrMap[utils.ToInt(dataRelation.Key)]
//	switch info.Key {
//	case "allHealth":
//		showAttr.Health += dataRelation.Number
//	case "attack":
//		showAttr.Attack += dataRelation.Number
//	case "defense":
//		showAttr.Defense += dataRelation.Number
//	}
//}
//
//func (attr ShowAttr) Merge(show *ShowAttr) {
//	attr.Health += show.Health
//	attr.Attack += show.Attack
//	attr.Defense += show.Defense
//	attr.AttackSpeed += show.AttackSpeed
//	attr.AttackDistance += show.AttackDistance
//	attr.Speed += show.Speed
//	attr.View += show.View
//}

//msgp:tuple ShowText
type ShowText struct {
	Type  string   `json:"type" msg:"type"`
	Value []string `json:"value" msg:"value"`
}

//msgp ShowTextSlice
type ShowTextSlice []ShowText

//msgp ShowTextShowSlice
type ShowTextShowSlice [][]string

func (slice ShowTextSlice) Format(language *language.LanguageData) ShowTextShowSlice {
	list := make(ShowTextShowSlice, len(slice))
	for index, item := range slice {
		list[index] = item.Value
	}
	return list
}

//msgp:tuple DataRelationShow
type DataRelationShow struct {
	Type        DataRelationType `json:"type" msg:"type"`
	Key         string           `json:"key" msg:"key"`
	Value       int              `json:"value" msg:"value"`
	LanguageKey string           `json:"languageKey" msg:"languageKey"`
}

//msgp DataRelationShowSlice
type DataRelationShowSlice []DataRelationShow

//msgp:tuple CompareDataRelationShow
type CompareDataRelationShow struct {
	Type        DataRelationType `json:"type" msg:"type"`
	Key         string           `json:"key" msg:"key"`
	Value       int              `json:"value" msg:"value"`
	Compare     byte             `json:"compare" msg:"compare"`
	LanguageKey string           `json:"languageKey" msg:"languageKey"`
}

//msgp CompareDataRelationShowSlice
type CompareDataRelationShowSlice []CompareDataRelationShow

//msgp:tuple DataRelationReachShow
type DataRelationReachShow struct {
	Type        DataRelationType `json:"type" msg:"type"`
	Key         string           `json:"key" msg:"key"`
	Value       int              `json:"value" msg:"value"`
	LanguageKey string           `json:"languageKey" msg:"languageKey"`

	Reach       string `json:"reach" msg:"reach"`
	UnReach     string `json:"unreach" msg:"unreach"`
	UnReachText string `json:"unreach_text" msg:"unreach_text"`
}

//msgp DataRelationReachShowSlice
type DataRelationReachShowSlice []DataRelationReachShow

//msgp:tuple CompareDataRelationReachShow
type CompareDataRelationReachShow struct {
	Type        DataRelationType `json:"type" msg:"type"`
	Key         string           `json:"key" msg:"key"`
	Value       int              `json:"value" msg:"value"`
	Compare     byte             `json:"compare" msg:"compare"`
	LanguageKey string           `json:"languageKey" msg:"languageKey"`

	Reach       string `json:"reach" msg:"reach"`
	UnReach     string `json:"unreach" msg:"unreach"`
	UnReachText string `json:"unreach_text" msg:"unreach_text"`
}

//msgp CompareDataRelationReachShowSlice
type CompareDataRelationReachShowSlice []CompareDataRelationReachShow

//msgp:tuple DataRelationTextShow
type DataRelationTextShow struct {
	Type        DataRelationType `json:"type" msg:"type"`
	Key         string           `json:"key" msg:"key"`
	Value       int              `json:"value" msg:"value"`
	LanguageKey string           `json:"languageKey" msg:"languageKey"`

	Reach       string `json:"reach" msg:"reach"`
	UnReach     string `json:"unreach" msg:"unreach"`
	UnReachText string `json:"unreach_text" msg:"unreach_text"`
}

//msgp DataRelationTextShowSlice
type DataRelationTextShowSlice []DataRelationTextShow

//msgp:tuple CompareDataRelationTextShow
type CompareDataRelationTextShow struct {
	Type        DataRelationType `json:"type" msg:"type"`
	Key         string           `json:"key" msg:"key"`
	Value       int              `json:"value" msg:"value"`
	Compare     byte             `json:"compare" msg:"compare"`
	LanguageKey string           `json:"languageKey" msg:"languageKey"`

	Text string `json:"text" msg:"text"`
}

//msgp CompareDataRelationTextShowSlice
type CompareDataRelationTextShowSlice []CompareDataRelationTextShow

//msgp:tuple BindOperationInfo
type BindOperationInfo struct {
	Require CompareDataRelationTextShowSlice `json:"require" msg:"require"`
	Consume DataRelationReachShowSlice       `json:"consume" msg:"consume"`
}

//msgp:tuple CompareInfo
type CompareInfo struct {
	Value   int  `json:"value" msg:"value"`
	Compare byte `json:"compare" msg:"compare"`
}

func (compare *CompareInfo) Valid(value int) bool {
	switch compare.Compare {
	case 0:
		return value == compare.Value
	case 1:
		return value > compare.Value
	case 2:
		return value < compare.Value
	case 3:
		return value >= compare.Value
	case 4:
		return value <= compare.Value
	}
	return false
}

//msgp:tuple Require
type Require struct {
	// 科技树要求
	Sciences map[int]CompareInfo `json:"sciences" msg:"sciences"`
	// 天赋要求
	Powers map[int]CompareInfo `json:"powers" msg:"powers"`
	// 用户拥有值
	User map[int]CompareInfo `json:"user" msg:"user"`
	// 使用者拥有值
	Owner map[int]CompareInfo `json:"owner" msg:"owner"`
}

//msgp:tuple Consume
type Consume struct {
	// 消耗用户数据
	User map[int]int `json:"user" msg:"user"`
	// 消耗用户道具
	Props map[int]int `json:"props" msg:"props"`
	// 使用者拥有值
	Owner map[int]int `json:"owner" msg:"owner"`
}

func NewConsume() *Consume {
	c := &Consume{
		User:  map[int]int{},
		Props: map[int]int{},
		Owner: map[int]int{},
	}
	return c
}

func (consume *Consume) Merge(other *Consume) {
	for key, value := range other.User {
		v, ok := consume.User[key]
		if ok {
			value += v
		}
		consume.User[key] = value
	}
	for key, value := range other.Props {
		v, ok := consume.Props[key]
		if ok {
			value += v
		}
		consume.Props[key] = value
	}
	for key, value := range other.Owner {
		v, ok := consume.Owner[key]
		if ok {
			value += v
		}
		consume.Owner[key] = value
	}
}

//msgp:tuple Receive
type Receive struct {
	// 获取用户数据
	User map[int]int `json:"user" msg:"user"`
	// 获取用户道具
	Props map[int]int `json:"props" msg:"props"`
	// 获取用户道具
	Equips map[int]int `json:"equips" msg:"equips"`
}

//msgp:tuple Effect
type Effect struct {
	// 获取指令
	DirectIds []int `json:"directIds" msg:"directIds"`
	// 附加的持久buff
	BuffIds []int `json:"buffIds" msg:"buffIds"`

	Attrs game.IntAbilitySlice `json:"attrs" msg:"attrs"`
	// 内部属性计算: 完整列表
	InlineAttrs game.IntAbilityMap `json:"-" msg:"-"`
}

func NewEffect() *Effect {
	effect := &Effect{
		InlineAttrs: game.IntAbilityMap{},
	}
	return effect
}

func (effect *Effect) Merge(e *Effect) {
	effect.DirectIds = append(effect.DirectIds, e.DirectIds...)
	effect.BuffIds = append(effect.BuffIds, e.BuffIds...)
	effect.InlineAttrs.MergeSlice(e.Attrs)
}

func (effect *Effect) Compute() {
	effect.DirectIds = utils.RemoveDuplicateInt(effect.DirectIds)
	effect.DirectIds = DefaultModelData.DistinctDirect(effect.DirectIds)
	effect.BuffIds = utils.RemoveDuplicateInt(effect.BuffIds)
	effect.BuffIds = DefaultSkillData.DistinctBuff(effect.BuffIds)
	effect.Attrs = effect.InlineAttrs.ToList()
}

func (effect *Effect) GetIds(define cooperate.AbilityDefine) []int {
	switch define {
	case DirectAbilityDefine:
		return effect.DirectIds
	case BuffAbilityDefine:
		return effect.BuffIds
	}
	return nil
}
func (effect *Effect) GetSlice(define cooperate.AbilityDefine) []int {
	switch define {
	case AttrAbilityDefine:
		return effect.Attrs
	}
	return nil
}
func (effect *Effect) MergeTo(e cooperate.AbilityEffect) cooperate.AbilityEffect {
	var ee *Effect
	if e == nil {
		ee = NewEffect()
	} else {
		ee = e.(*Effect)
	}
	ee.Merge(effect)
	//fmt.Println("effect", e, ee)
	ee.Compute()
	return ee
}
func (effect *Effect) ChangeSlice(define cooperate.AbilityDefine, index int, value int) {
	switch define {
	case AttrAbilityDefine:
		effect.InlineAttrs[index] = value
		effect.Attrs = effect.InlineAttrs.ToList()
	}
}

// 发送给客户端显示
//msgp:tuple UnitEffect
type UnitEffect struct {
	DirectIds []int `json:"direct_ids" msg:"direct_ids"`

	Attrs    []int `json:"attrs" msg:"attrs"`
	AllAttrs []int `json:"all_attrs" msg:"all_attrs"`
}

func (uef *UnitEffect) Base(directIds []int, modelData *ModelData) {
	uef.DirectIds = directIds
}

//msgp:tuple SustainSetting
type SustainSetting struct {
	Type     int           `json:"type" msg:"type"`
	Params   []interface{} `json:"params" msg:"params"`
	CanBreak bool          `json:"can_break" msg:"can_break"`
}

//msgp:tuple PropInUser
type PropInUser struct {
	PropId int `json:"prop_id" msg:"prop_id"`
	Number int `json:"number" msg:"number"`
}

//msgp:tuple EquipInUser
type EquipInUser struct {
	UserEquipId int    `json:"user_equip_id" msg:"user_equip_id"`
	EquipId     int    `json:"equip_id" msg:"equip_id"`
	Location    string `json:"location" msg:"location"`
	Level       int    `json:"level" msg:"level"`
}

//msgp:tuple BuildLevel
type BuildLevel struct {
	Show        []interface{} `json:"show" msg:"show"`
	CanDefense  bool          `json:"can_defense" msg:"can_defense"`
	DefendRange byte          `json:"defend_range" msg:"defend_range"`
	RecoverTime int           `json:"recover_time" msg:"recover_time"`
	BuildTime   int           `json:"build_time" msg:"build_time"`

	Level int    `json:"level" msg:"level"`
	Name  string `json:"name" msg:"name"`
	Desc  string `json:"desc" msg:"desc"`

	Require CompareDataRelationTextShowSlice `json:"require" msg:"require"`
	Consume DataRelationReachShowSlice       `json:"consume" msg:"consume"`
	Effect  ShowTextShowSlice                `json:"effect" msg:"effect"`

	SyncDefault []int `json:"sync_default" msg:"sync_default"`

	RequireSlice *Require `json:"-" msg:"-"`
	ConsumeSlice *Consume `json:"-" msg:"-"`
	EffectSlice  *Effect  `json:"-" msg:"-"`

	*game.DataInlineExtend `json:"-" msg:"-"`
}

func NewBuildLevel(language *language.LanguageData, provider *game.DataProvider, parentExtend *game.DataExtend, level *DefineBuildLevel) BuildLevel {
	extend := game.NewDataInlineExtend(utils.ToString(level.Level)).Add("name", level.Name).Add("desc", level.Desc)
	parentExtend.Attach("level", extend)
	if level.Show == nil {
		level.Show = []interface{}{}
	}

	l := BuildLevel{
		Level:       level.Level,
		Name:        provider.LanguageKey(extend, "name"),
		Desc:        provider.LanguageKey(extend, "desc"),
		Show:        level.Show,
		CanDefense:  level.CanDefense,
		DefendRange: level.DefendRange,
		RecoverTime: level.RecoverTime,
		BuildTime:   level.BuildTime,
		Require:     level.Require.TextShow(),
		Consume:     level.Consume.ReachShow(),
		Effect:      level.EffectText.Format(language),

		RequireSlice: level.Require.Require(),
		ConsumeSlice: level.Consume.Consume(),
		EffectSlice:  level.Effect.Effect(),
		SyncDefault:  level.SyncDefault,

		DataInlineExtend: extend,
	}
	return l
}

//msgp:tuple BuildInfo
type BuildInfo struct {
	Id       int    `json:"id" msg:"id"`
	Key      string `json:"key" msg:"key"`
	Type     byte   `json:"type" msg:"type"`
	Range    uint16 `json:"range" msg:"range"`
	FixRange int    `json:"fixRange" msg:"fixRange"`

	Name string `json:"name" msg:"name"`
	Desc string `json:"desc" msg:"desc"`

	Require     CompareDataRelationTextShowSlice `json:"require" msg:"require"`
	Consume     DataRelationReachShowSlice       `json:"consume" msg:"consume"`
	SyncKeys    []string                         `json:"sync_keys" msg:"sync_keys"`
	SyncDefault []int                            `json:"sync_default" msg:"sync_default"`
}

//msgp:tuple Build
type Build struct {
	Id         int          `json:"id" msg:"id"`
	Key        string       `json:"key" msg:"key"`
	Type       byte         `json:"type" msg:"type"`
	Range      uint16       `json:"range" msg:"range"`
	FixRange   int          `json:"fixRange" msg:"fixRange"`
	CanDestroy bool         `json:"can_destroy" msg:"can_destroy"`
	Levels     []BuildLevel `json:"levels" msg:"levels"`

	Name     string   `json:"name" msg:"name"`
	Desc     string   `json:"desc" msg:"desc"`
	SyncKeys []string `json:"sync_keys" msg:"sync_keys"`

	CanUnit            bool     `json:"-" msg:"-"`
	FilterRequireSlice *Require `json:"-" msg:"-"`
	DestroyItem        int      `json:"-" msg:"-"`
	NeedManage         bool     `json:"-" msg:"-"`

	AttackRangeMask int `json:"-" msg:"-"`

	SyncKeyMap map[string]int `json:"-" msg:"-"`

	*game.DataExtend `json:"-" msg:"-"`
	Info             *BuildInfo `json:"-" msg:"-"`
}

func NewBuild(syncData *sync.SyncData, language *language.LanguageData, provider *game.DataProvider, build *DefineBuild, levels []*DefineBuildLevel) *Build {
	extend := game.NewDataExtend(utils.ToString(build.Id), build.UpdateTime).Add("name", build.Name).Add("desc", build.Desc)

	dt := &Build{
		Id:         build.Id,
		Key:        build.Key,
		Name:       provider.LanguageKey(extend.Inline(), "name"),
		Desc:       provider.LanguageKey(extend.Inline(), "desc"),
		Type:       build.Type,
		Range:      utils.ToUint16(utils.ConcatInt(syncData.MappingLevel(build.Range))),
		FixRange:   build.FixRange,
		CanDestroy: build.CanDestroy,

		CanUnit:            build.CanUnit,
		FilterRequireSlice: build.FilterRequire.Require(),
		DestroyItem:        build.DestroyItem,
		NeedManage:         build.NeedManage,
		AttackRangeMask:    utils.ConcatInt(build.AttackRangeMask),
		SyncKeys:           build.SyncKeys,
		SyncKeyMap:         utils.StringArrayToMap(build.SyncKeys),
		DataExtend:         extend,
	}
	level := make([]BuildLevel, len(levels))
	for i := 0; i < len(level); i++ {
		l := NewBuildLevel(language, provider, extend, levels[i])
		level[i] = l
	}
	dt.Levels = level
	if len(level) > 0 {
		dt.Info = &BuildInfo{
			Id:          dt.Id,
			Key:         dt.Key,
			Type:        dt.Type,
			Range:       dt.Range,
			FixRange:    dt.FixRange,
			Name:        dt.Name,
			Desc:        dt.Desc,
			Require:     dt.Levels[0].Require,
			Consume:     dt.Levels[0].Consume,
			SyncKeys:    dt.SyncKeys,
			SyncDefault: dt.Levels[0].SyncDefault,
		}
	}

	return dt
}

//msgp:tuple UnitLevel
type UnitLevel struct {
	Show        []interface{} `json:"show" msg:"show"`
	RecoverTime int           `json:"recover_time" msg:"recover_time"`
	PowerPoint  int           `json:"power_point" msg:"power_point"`

	Level int    `json:"level" msg:"level"`
	Name  string `json:"name" msg:"name"`
	Desc  string `json:"desc" msg:"desc"`

	// 升级条件：经验值
	Require CompareDataRelationTextShowSlice `json:"require" msg:"require"`
	Consume DataRelationReachShowSlice       `json:"consume" msg:"consume"`
	Effect  ShowTextShowSlice                `json:"effect" msg:"effect"`

	SyncDefault []int `json:"sync_default" msg:"sync_default"`

	RequireSlice *Require `json:"-" msg:"-"`
	ConsumeSlice *Consume `json:"-" msg:"-"`
	EffectSlice  *Effect  `json:"-" msg:"-"`

	*game.DataInlineExtend `json:"-" msg:"-"`
}

func NewUnitLevel(language *language.LanguageData, provider *game.DataProvider, parentExtend *game.DataExtend, level *DefineUnitLevel) UnitLevel {
	extend := game.NewDataInlineExtend(utils.ToString(level.Level)).Add("name", level.Name).Add("desc", level.Desc)
	parentExtend.Attach("level", extend)
	if level.Show == nil {
		level.Show = []interface{}{}
	}
	l := UnitLevel{
		Level:       level.Level,
		Name:        provider.LanguageKey(extend, "name"),
		Desc:        provider.LanguageKey(extend, "desc"),
		Show:        level.Show,
		RecoverTime: level.RecoverTime,
		PowerPoint:  level.PowerPoint,
		Require:     level.Require.TextShow(),
		Consume:     level.Consume.ReachShow(),
		Effect:      level.EffectText.Format(language),

		RequireSlice: level.Require.Require(),
		ConsumeSlice: level.Consume.Consume(),
		EffectSlice:  level.Effect.Effect(),
		SyncDefault:  level.SyncDefault,

		DataInlineExtend: extend,
	}
	return l
}

//msgp:tuple UnitInfo
type UnitInfo struct {
	Id         int    `json:"id" msg:"id"`
	Key        string `json:"key" msg:"key"`
	Type       byte   `json:"type" msg:"type"`
	Range      uint16 `json:"range" msg:"range"`
	TargetMode int    `json:"target_mode" msg:"target_mode"`

	Name string `json:"name" msg:"name"`
	Desc string `json:"desc" msg:"desc"`

	Require     CompareDataRelationTextShowSlice `json:"require" msg:"require"`
	Consume     DataRelationReachShowSlice       `json:"consume" msg:"consume"`
	SyncKeys    []string                         `json:"sync_keys" msg:"sync_keys"`
	SyncDefault []int                            `json:"sync_default" msg:"sync_default"`
}

//msgp:tuple Unit
type Unit struct {
	Id         int         `json:"id" msg:"id"`
	Key        string      `json:"key" msg:"key"`
	Type       byte        `json:"type" msg:"type"`
	Range      uint16      `json:"range" msg:"range"`
	TargetMode int         `json:"target_mode" msg:"target_mode"`
	CanDestroy bool        `json:"can_destroy" msg:"can_destroy"`
	CanAi      bool        `json:"can_ai" msg:"can_ai"`
	Levels     []UnitLevel `json:"levels" msg:"levels"`

	Name     string   `json:"name" msg:"name"`
	Desc     string   `json:"desc" msg:"desc"`
	SyncKeys []string `json:"sync_keys" msg:"sync_keys"`

	CanCreate          bool     `json:"-" msg:"-"`
	FilterRequireSlice *Require `json:"-" msg:"-"`
	DestroyItem        int      `json:"-" msg:"-"`

	SelfMask        int `json:"-" msg:"-"`
	OtherMask       int `json:"-" msg:"-"`
	OtherAutoMask   int `json:"-" msg:"-"`
	AttackRangeMask int `json:"-" msg:"-"`
	AttackRouteMask int `json:"-" msg:"-"`

	SyncKeyMap map[string]int `json:"-" msg:"-"`

	*game.DataExtend `json:"-" msg:"-"`
	Info             *UnitInfo `json:"-" msg:"-"`
}

func NewUnit(syncData *sync.SyncData, language *language.LanguageData, provider *game.DataProvider, unit *DefineUnit, levels []*DefineUnitLevel) *Unit {
	extend := game.NewDataExtend(utils.ToString(unit.Id), unit.UpdateTime).Add("name", unit.Name).Add("desc", unit.Desc)

	dt := &Unit{
		Id:         unit.Id,
		Key:        unit.Key,
		Type:       unit.Type,
		Range:      utils.ToUint16(utils.ConcatInt(syncData.MappingLevel(unit.Range))),
		Name:       provider.LanguageKey(extend.Inline(), "name"),
		Desc:       provider.LanguageKey(extend.Inline(), "desc"),
		TargetMode: unit.OrderMode | unit.TargetMode,
		CanDestroy: unit.CanDestroy,
		CanAi:      unit.CanAi,

		CanCreate:          unit.CanCreate,
		FilterRequireSlice: unit.FilterRequire.Require(),
		DestroyItem:        unit.DestroyItem,
		SelfMask:           utils.ConcatInt(unit.SelfMask),
		OtherMask:          utils.ConcatInt(unit.OtherMask),
		OtherAutoMask:      utils.ConcatInt(unit.OtherAutoMask),
		AttackRangeMask:    utils.ConcatInt(unit.AttackRangeMask),
		AttackRouteMask:    utils.ConcatInt(unit.AttackRouteMask),
		SyncKeys:           unit.SyncKeys,
		SyncKeyMap:         utils.StringArrayToMap(unit.SyncKeys),

		DataExtend: extend,
	}
	level := make([]UnitLevel, len(levels))
	for i := 0; i < len(level); i++ {
		l := NewUnitLevel(language, provider, extend, levels[i])
		level[i] = l
	}
	dt.Levels = level
	if len(level) > 0 {
		dt.Info = &UnitInfo{
			Id:          dt.Id,
			Key:         dt.Key,
			Type:        dt.Type,
			Range:       dt.Range,
			TargetMode:  dt.TargetMode,
			Name:        dt.Name,
			Desc:        dt.Desc,
			Require:     dt.Levels[0].Require,
			Consume:     dt.Levels[0].Consume,
			SyncKeys:    dt.SyncKeys,
			SyncDefault: dt.Levels[0].SyncDefault,
		}
	}
	return dt
}

//msgp:tuple Node
type Node struct {
	Id    int           `json:"id" msg:"id"`
	Key   string        `json:"key" msg:"key"`
	Type  byte          `json:"type" msg:"type"`
	Range uint16        `json:"range" msg:"range"`
	Show  []interface{} `json:"show" msg:"show"`

	LogicRange  int      `json:"logic_range" msg:"logic_range"`
	SyncKeys    []string `json:"sync_keys" msg:"sync_keys"`
	SyncDefault []int    `json:"sync_default" msg:"sync_default"`

	OnlyPath bool `json:"-" msg:"-"`

	NeedManage       bool           `json:"-" msg:"-"`
	SyncKeyMap       map[string]int `json:"-" msg:"-"`
	*game.DataExtend `json:"-" msg:"-"`
}

func NewNode(syncData *sync.SyncData, provider *game.DataProvider, node *DefineNode) *Node {
	if node.Show == nil {
		node.Show = []interface{}{}
	}
	dt := &Node{
		Id:          node.Id,
		Key:         node.Key,
		Type:        node.Type,
		Range:       utils.ToUint16(utils.ConcatInt(syncData.MappingLevel(node.Range))),
		Show:        node.Show,
		NeedManage:  node.NeedManage,
		LogicRange:  node.LogicRange,
		SyncKeys:    node.SyncKeys,
		SyncDefault: node.SyncDefault,
		SyncKeyMap:  utils.StringArrayToMap(node.SyncKeys),
		OnlyPath:    node.OnlyPath,

		DataExtend: game.NewDataExtend(utils.ToString(node.Id), node.UpdateTime),
	}
	return dt
}

//msgp:tuple Item
type Item struct {
	Id          int           `json:"id" msg:"id"`
	Key         string        `json:"key" msg:"key"`
	Type        byte          `json:"type" msg:"type"`
	Range       uint16        `json:"range" msg:"range"`
	CanDefense  bool          `json:"can_defense" msg:"can_defense"`
	DefendRange byte          `json:"defend_range" msg:"defend_range"`
	Show        []interface{} `json:"show" msg:"show"`
	SelfDestroy bool          `json:"self_destroy" msg:"self_destroy"`
	NeedReceive bool          `json:"need_receive" msg:"need_receive"`

	EffectSlice *Effect `json:"effect" msg:"effect"`

	Name        string   `json:"name" msg:"name"`
	Desc        string   `json:"desc" msg:"desc"`
	SyncKeys    []string `json:"sync_keys" msg:"sync_keys"`
	SyncDefault []int    `json:"sync_default" msg:"sync_default"`

	NeedManage       bool                  `json:"-" msg:"-"`
	SyncKeyMap       map[string]int        `json:"-" msg:"-"`
	AttackRangeMask  int                   `json:"-" msg:"-"`
	Receive          DataRelationShowSlice `json:"-" msg:"-"`
	ReceiveSlice     *Receive              `json:"-" msg:"-"`
	*game.DataExtend `json:"-" msg:"-"`
}

func NewItem(syncData *sync.SyncData, provider *game.DataProvider, item *DefineItem) *Item {
	extend := game.NewDataExtend(utils.ToString(item.Id), item.UpdateTime).Add("name", item.Name).Add("desc", item.Desc)
	if item.Show == nil {
		item.Show = []interface{}{}
	}
	dt := &Item{
		Id:          item.Id,
		Key:         item.Key,
		Type:        item.Type,
		Range:       utils.ToUint16(utils.ConcatInt(syncData.MappingLevel(item.Range))),
		CanDefense:  item.CanDefense,
		DefendRange: item.DefendRange,
		Show:        item.Show,
		SelfDestroy: item.SelfDestroy,
		NeedReceive: item.Receive != nil && len(item.Receive) > 0,

		EffectSlice: item.Effect.Effect(),

		Name: provider.LanguageKey(extend.Inline(), "name"),
		Desc: provider.LanguageKey(extend.Inline(), "desc"),

		NeedManage:      item.NeedManage,
		AttackRangeMask: utils.ConcatInt(item.AttackRangeMask),
		SyncKeys:        item.SyncKeys,
		SyncDefault:     item.SyncDefault,
		SyncKeyMap:      utils.StringArrayToMap(item.SyncKeys),
		DataExtend:      extend,
	}
	if item.Receive != nil {
		dt.Receive = item.Receive.Show()
		dt.ReceiveSlice = item.Receive.Receive()
	}
	return dt
}

//msgp:tuple Direct
type Direct struct {
	Id             int        `json:"id" msg:"id"`
	Icon           string     `json:"icon" msg:"icon"`
	IconType       string     `json:"icon_type" msg:"icon_type"`
	Range          byte       `json:"range" msg:"range"`
	MaxDistance    byte       `json:"max_distance" msg:"max_distance"`
	AutoMove       bool       `json:"auto_move" msg:"auto_move"`
	CoolTime       int        `json:"cool_time" msg:"cool_time"`             // 冷却时间
	ReadyTime      int        `json:"ready_time" msg:"ready_time"`           // 准备释放
	CastTime       int        `json:"cast_time" msg:"cast_time"`             // 释放时间
	SustainedTime  int        `json:"sustained_time" msg:"sustained_time"`   //持续时间
	IntervalTime   int        `json:"interval_time" msg:"interval_time"`     // 间隔时间
	Multi          byte       `json:"multi" msg:"Multi"`                     // 多攻击目标
	TargetIdentity int        `json:"target_identity" msg:"target_identity"` // 目标模式
	Mode           DirectMode `json:"mode" msg:"mode"`
	TargetMode     TargetMode `json:"target_mode" msg:"target_mode"`
	OperationId    int        `json:"operation_id" msg:"operation_id"`

	ScheduleType cooperate.LogicType `json:"schedule_type" msg:"schedule_type"`
	Params       []string            `json:"params" msg:"params"`
	Default      []interface{}       `json:"default" msg:"default"`

	Effect ShowTextShowSlice `json:"effect" msg:"effect"`

	Name string `json:"name" msg:"name"`
	Desc string `json:"desc" msg:"desc"`

	TargetMap        map[structure.PublicDataType]map[int]struct{} `json:"-" msg:"-"`
	Targets          []structure.PublicDataType                    `json:"-" msg:"-"`
	*game.DataExtend `json:"-" msg:"-"`
	Direct           *SettingDirect `json:"-" msg:"-"`

	Define      int `json:"-" msg:"-"`
	DefineLevel int `json:"-" msg:"-"`

	CoolSave       bool            `json:"-" msg:"-"`
	CancelDestroy  bool            `json:"-" msg:"-"`
	SustainSetting *SustainSetting `json:"-" msg:"-"`
}

func (direct *Direct) ValidTarget(dataType structure.PublicDataType, typeId int) bool {
	if len(direct.TargetMap) == 0 {
		return true
	}
	pm, ok := direct.TargetMap[dataType]
	if !ok {
		return ok
	}
	if len(pm) == 0 {
		return true
	}
	_, o := pm[typeId]
	return o
}

func (direct *Direct) GetScheduleKey() string {
	logicKey := "use" + utils.ToString(direct.Id)
	if direct.CancelDestroy {
		logicKey = "process"
	}
	return logicKey
}

func NewDirect(language *language.LanguageData, provider *game.DataProvider, direct *SettingDirect) *Direct {
	extend := game.NewDataExtend(utils.ToString(direct.Id), direct.UpdateTime).Add("name", direct.Name).Add("desc", direct.Desc)
	d := &Direct{
		Id:             direct.Id,
		Name:           provider.LanguageKey(extend.Inline(), "name"),
		Desc:           provider.LanguageKey(extend.Inline(), "desc"),
		Icon:           direct.Icon,
		IconType:       direct.IconType,
		Range:          direct.Range,
		MaxDistance:    direct.MaxDistance,
		AutoMove:       direct.AutoMove,
		CoolTime:       utils.ToInt(direct.CoolTime),
		ReadyTime:      utils.ToInt(direct.ReadyTime),
		CastTime:       utils.ToInt(direct.CastTime),
		SustainedTime:  utils.ToInt(direct.SustainedTime),
		IntervalTime:   utils.ToInt(direct.IntervalTime),
		Multi:          direct.Multi,
		TargetIdentity: utils.ConcatIntByte(direct.TargetIdentity),

		Mode:        direct.Mode,
		TargetMode:  direct.TargetMode,
		OperationId: direct.OperationId,
		Effect:      direct.EffectText.Format(language),

		DataExtend: extend,
		Direct:     direct,

		CoolSave:       direct.CoolSave,
		CancelDestroy:  direct.CancelDestroy,
		SustainSetting: direct.Sustain,

		ScheduleType: direct.ScheduleType,
		Default:      direct.Default,

		Define:      direct.Define,
		DefineLevel: direct.DefineLevel,
	}
	// 预处理
	d.Pre(direct)
	return d
}
func (item *Direct) Pre(direct *SettingDirect) {
	item.Params = []string{}
	for index := range direct.Params {
		if len(direct.Default) <= index || direct.Default[index] == nil {
			item.Params = append(item.Params, direct.Params[index])
		}
	}
	item.TargetMap = map[structure.PublicDataType]map[int]struct{}{}
	item.Targets = []structure.PublicDataType{}
	if direct.TargetSelect != nil {
		for _, target := range direct.TargetSelect {
			item.TargetMap[target.Type] = map[int]struct{}{}
			for _, k := range target.Ids {
				item.TargetMap[target.Type][k] = struct{}{}
			}
			item.Targets = append(item.Targets, target.Type)
		}
	}
	switch direct.TargetMode {
	case SingleTargetMode:
		item.Multi = 1
		item.Range = 1
	case SelfTargetMode:
		item.Multi = 1
		item.Range = 1
		item.TargetIdentity = 2
	case RangeTargetMode:
	}
}

func (item *Direct) Fill(params []interface{}) ([]interface{}, error) {
	if len(params) != len(item.Params) {
		return nil, errors.New("param len is err")
	}
	result := make([]interface{}, len(item.Direct.Params))
	i := 0
	for index := range item.Direct.Params {
		if len(item.Direct.Default) <= index || item.Direct.Default[index] == nil {
			result[index] = params[i]
			i++
		} else {
			result[index] = item.Direct.Default[index]
		}
	}
	return result, nil
}

type Operation struct {
	Id       int    `json:"id" msg:"id"`
	Icon     string `json:"icon" msg:"icon"`
	IconType string `json:"icon_type" msg:"icon_type"`

	Type   OperationType `json:"type" sql:"TINYINT"`
	Key    string        `json:"key" msg:"key"`
	Params []string      `json:"params" msg:"params"`
	Show   int           `json:"show" msg:"show"`

	Name string `json:"name" msg:"name"`
	Desc string `json:"desc" msg:"desc"`

	Require          *Require `json:"-" msg:"-"`
	UnitRequire      *Require `json:"-" msg:"-"`
	TargetRequire    *Require `json:"-" msg:"-"`
	*game.DataExtend `json:"-" msg:"-"`

	UseConsumeSlice DataRelationReachShowSlice `json:"-" msg:"-"`
	UseConsume      *Consume                   `json:"-" msg:"-"`
	Operation       *SettingOperation          `json:"-" msg:"-"`
	Targets         []structure.PublicDataType `json:"-" msg:"-"`
}

func NewOperation(provider *game.DataProvider, operation *SettingOperation) *Operation {
	extend := game.NewDataExtend(utils.ToString(operation.Id), operation.UpdateTime).Add("name", operation.Name).Add("desc", operation.Desc)

	d := &Operation{
		Id:       operation.Id,
		Icon:     operation.Icon,
		IconType: operation.IconType,

		Type: operation.Type,
		Key:  operation.Key,

		Name: provider.LanguageKey(extend.Inline(), "name"),
		Desc: provider.LanguageKey(extend.Inline(), "desc"),

		Require:       operation.Require.Require(),
		UnitRequire:   operation.UnitRequire.Require(),
		TargetRequire: operation.TargetRequire.Require(),

		UseConsume:      operation.UseConsume.Consume(),
		UseConsumeSlice: operation.UseConsume.ReachShow(),

		DataExtend: extend,
		Operation:  operation,
	}
	d.Pre(operation)
	return d
}

func (item *Operation) Pre(operation *SettingOperation) {
	item.Show = utils.ConcatInt(operation.Show)
	item.Params = []string{}
	for index := range operation.Params {
		if len(operation.Default) <= index || operation.Default[index] == nil {
			item.Params = append(item.Params, operation.Params[index])
		}
	}
	item.Targets = []structure.PublicDataType{}
	if operation.Target != nil {
		for _, target := range operation.Target {
			item.Targets = append(item.Targets, target.Type)
		}
	}
}

func (item *Operation) Fill(params []interface{}) ([]interface{}, error) {
	if len(params) != len(item.Params) {
		return nil, errors.New("param len is err")
	}
	result := make([]interface{}, len(item.Operation.Params))
	i := 0
	for index := range item.Operation.Params {
		if len(item.Operation.Default) <= index || item.Operation.Default[index] == nil {
			result[index] = params[i]
			i++
		} else {
			result[index] = item.Operation.Default[index]
		}
	}
	return result, nil
}

func (item *Operation) FillDirect(direct *Direct, params []interface{}) ([]interface{}, error) {
	fmt.Println("op", params, item, direct)
	if len(params) != len(item.Params)+len(direct.Params) {
		return nil, errors.New("param len is err")
	}
	var result []interface{}
	result = make([]interface{}, len(item.Operation.Params)+1)
	i := 0
	for index := range item.Operation.Params {
		if len(item.Operation.Default) <= index || item.Operation.Default[index] == nil {
			result[index] = params[i]
			i++
		} else {
			result[index] = item.Operation.Default[index]
		}
	}
	// 将指令params写入最后一个result
	if len(direct.Params) > 0 {
		result[len(item.Operation.Params)] = params[i:]
	} else {
		result[len(item.Operation.Params)] = []interface{}{}
	}
	return result, nil
}

func (item *Operation) Filter(relation OperationShow) bool {
	if item.Show == 0 {
		// 不过滤
		return true
	}
	return utils.IncludeIntByte(item.Show, utils.ToInt(relation))
}

//msgp:tuple OperationInstance
type OperationInstance struct {
	Id       int    `json:"id" msg:"id"`
	Icon     string `json:"icon" msg:"icon"`
	IconType string `json:"icon_type" msg:"icon_type"`
	// 参数定义中会告知是否需要返回指令
	DirectId int    `json:"direct_id" msg:"direct_id"`
	Key      string `json:"key" msg:"key"`
	// 如果是指令操作，Require走指令逻辑
	Require  CompareDataRelationTextShowSlice `json:"require" msg:"require"`
	Consume  DataRelationReachShowSlice       `json:"consume" msg:"consume"`
	CoolTime int64                            `json:"cool_time" msg:"cool_time"`
	// 过滤默认值后，还需提交的参数列表
	Params []string `json:"params" msg:"params"`

	Name string `json:"name" msg:"name"`
	Desc string `json:"desc" msg:"desc"`

	Show    []uint                     `json:"show" msg:"show"`
	Targets []structure.PublicDataType `json:"targets" msg:"targets"`
}

func NewOperationInstance(operation *Operation, direct *Direct, coolTime int64, require CompareDataRelationTextShowSlice, consume DataRelationReachShowSlice) *OperationInstance {
	d := &OperationInstance{
		Id:       operation.Id,
		Icon:     operation.Icon,
		IconType: operation.IconType,
		Key:      operation.Key,
		Name:     operation.Name,
		Desc:     operation.Desc,
		Require:  require,
		Consume:  consume,
		Params:   operation.Params,
		Show:     operation.Operation.Show,
		Targets:  operation.Targets,
	}
	if direct != nil {
		d.Icon = direct.Icon
		d.IconType = direct.IconType
		d.DirectId = direct.Id
		d.Name = direct.Name
		d.Desc = direct.Desc
		d.CoolTime = coolTime
		d.Targets = direct.Targets
		// 将指令的params写入操作params
		d.Params = append(d.Params, direct.Params...)
	}
	//if require != nil {
	//	d.Require = require
	//}
	//if consume != nil {
	//	d.Consume = consume
	//}
	return d
}

//msgp:tuple EquipLevel
type EquipLevel struct {
	Level int    `json:"level" msg:"level"`
	Name  string `json:"name" msg:"name"`
	Desc  string `json:"desc" msg:"desc"`
	// 升级条件
	Require CompareDataRelationReachShowSlice `json:"require" msg:"require"`
	// 安装效果
	Effect ShowTextShowSlice `json:"effect" msg:"effect"`
	// 分解所得
	Decompose DataRelationTextShowSlice `json:"decompose" msg:"decompose"`
	// 强化所需
	Intensify DataRelationReachShowSlice `json:"intensify" msg:"intensify"`

	// 升级条件
	RequireSlice *Require `json:"-" msg:"-"`
	// 安装效果
	EffectSlice *Effect `json:"-" msg:"-"`
	// 分解所得
	DecomposeSlice *Receive `json:"-" msg:"-"`
	// 强化所需
	IntensifySlice *Consume `json:"-" msg:"-"`

	*game.DataInlineExtend `json:"-" msg:"-"`
}

func NewEquipLevel(language *language.LanguageData, provider *game.DataProvider, parentExtend *game.DataExtend, equipLevel *SettingEquipLevel) EquipLevel {
	extend := game.NewDataInlineExtend(utils.ToString(equipLevel.Level)).Add("name", equipLevel.Name).Add("desc", equipLevel.Desc)
	parentExtend.Attach("level", extend)
	level := EquipLevel{
		Level:     equipLevel.Level,
		Name:      provider.LanguageKey(extend, "name"),
		Desc:      provider.LanguageKey(extend, "desc"),
		Require:   equipLevel.Require.ReachShow(),
		Effect:    equipLevel.EffectText.Format(language),
		Decompose: equipLevel.Decompose.TextShow(),
		Intensify: equipLevel.Intensify.ReachShow(),

		RequireSlice:   equipLevel.Require.Require(),
		EffectSlice:    equipLevel.Effect.Effect(),
		DecomposeSlice: equipLevel.Decompose.Receive(),
		IntensifySlice: equipLevel.Intensify.Consume(),

		DataInlineExtend: extend,
	}
	return level
}

//msgp:tuple Equip
type Equip struct {
	Id       int    `json:"id" msg:"id"`
	Name     string `json:"name" msg:"name"`
	Desc     string `json:"desc" msg:"desc"`
	Icon     string `json:"icon" msg:"icon"`
	Quality  int    `json:"quality" msg:"quality"`
	Location string `json:"location" msg:"location"`
	// 安装要求
	Require CompareDataRelationReachShowSlice `json:"require" msg:"require"`
	Levels  []EquipLevel                      `json:"level" msg:"level"`

	RequireSlice *Require `json:"-" msg:"-"`

	*game.DataExtend `json:"-" msg:"-"`
}

func NewEquip(language *language.LanguageData, provider *game.DataProvider, equip *SettingEquip, levels []*SettingEquipLevel) *Equip {
	extend := game.NewDataExtend(utils.ToString(equip.Id), equip.UpdateTime).Add("name", equip.Name).Add("desc", equip.Desc)
	se := &Equip{
		Id:       equip.Id,
		Name:     provider.LanguageKey(extend.Inline(), "name"),
		Desc:     provider.LanguageKey(extend.Inline(), "desc"),
		Icon:     equip.Icon,
		Quality:  equip.Quality,
		Location: equip.Location,
		Require:  equip.Require.ReachShow(),

		RequireSlice: equip.Require.Require(),

		DataExtend: extend,
	}
	level := make([]EquipLevel, len(levels))
	for i := 0; i < len(levels); i++ {
		l := NewEquipLevel(language, provider, extend, levels[i])
		level[i] = l
	}
	se.Levels = level
	return se
}

//msgp:tuple PowerLevel
type PowerLevel struct {
	Level int    `json:"level" msg:"level"`
	Name  string `json:"name" msg:"name"`
	Desc  string `json:"desc" msg:"desc"`
	// 天赋升级条件
	Require CompareDataRelationReachShowSlice `json:"require" msg:"require"`
	Consume DataRelationReachShowSlice        `json:"consume" msg:"consume"`
	// 天赋升级效果
	Effect ShowTextShowSlice `json:"effect" msg:"effect"`

	RequireSlice *Require `json:"-"`
	ConsumeSlice *Consume `json:"-"`
	EffectSlice  *Effect  `json:"-"`

	*game.DataInlineExtend `json:"-" msg:"-"`
}

func NewPowerLevel(language *language.LanguageData, provider *game.DataProvider, parentExtend *game.DataExtend, level *SettingPowerLevel) PowerLevel {
	extend := game.NewDataInlineExtend(utils.ToString(level.Level)).Add("name", level.Name).Add("desc", level.Desc)
	parentExtend.Attach("level", extend)
	l := PowerLevel{
		Level:   level.Level,
		Name:    provider.LanguageKey(extend, "name"),
		Desc:    provider.LanguageKey(extend, "desc"),
		Require: level.Require.ReachShow(),
		Consume: level.Consume.ReachShow(),
		Effect:  level.EffectText.Format(language),

		RequireSlice: level.Require.Require(),
		ConsumeSlice: level.Consume.Consume(),
		EffectSlice:  level.Effect.Effect(),

		DataInlineExtend: extend,
	}
	return l
}

//msgp:tuple Power
type Power struct {
	Id     int          `json:"id" msg:"id"`
	Key    string       `json:"key" msg:"key"`
	Name   string       `json:"name" msg:"name"`
	Desc   string       `json:"desc" msg:"desc"`
	Icon   string       `json:"icon" msg:"icon"`
	UnitId int          `json:"unit" msg:"unit"`
	Levels []PowerLevel `json:"level" msg:"level"`

	*game.DataExtend `json:"-" msg:"-"`
}

func NewPower(language *language.LanguageData, provider *game.DataProvider, power *SettingPower, levels []*SettingPowerLevel) *Power {
	extend := game.NewDataExtend(utils.ToString(power.Id), power.UpdateTime).Add("name", power.Name).Add("desc", power.Desc)
	se := &Power{
		Id:   power.Id,
		Key:  power.Key,
		Name: provider.LanguageKey(extend.Inline(), "name"),
		Desc: provider.LanguageKey(extend.Inline(), "desc"),
		Icon: power.Icon,

		UnitId: power.UnitId,

		DataExtend: extend,
	}
	level := make([]PowerLevel, len(levels))
	for i := 0; i < len(level); i++ {
		if levels[i] == nil {
			fmt.Println("power", i, se.Id, se.Name, levels[i])
			continue
		}

		l := NewPowerLevel(language, provider, extend, levels[i])
		level[i] = l
	}
	se.Levels = level
	return se
}

//msgp:tuple Prop
type Prop struct {
	Id       int      `json:"id" msg:"id"`
	Name     string   `json:"name" msg:"name"`
	Desc     string   `json:"desc" msg:"desc"`
	Icon     string   `json:"icon" msg:"icon"`
	CanSell  bool     `json:"can_sell" msg:"can_sell"`
	Mode     PropMode `json:"mode" msg:"mode"`
	DirectId int      `json:"direct_id" msg:"direct_id"`
	// 安装条件
	Require CompareDataRelationReachShowSlice `json:"require" msg:"require"`
	// 使用效果
	Effect      ShowTextShowSlice         `json:"effect" msg:"effect"`
	Receive     DataRelationTextShowSlice `json:"receive" msg:"receive"`
	SellReceive DataRelationTextShowSlice `json:"sell_receive" msg:"sell_receive"`

	RequireSlice     *Require `json:"-" msg:"-"`
	ReceiveSlice     *Receive `json:"-" msg:"-"`
	SellReceiveSlice *Receive `json:"-" msg:"-"`
	EffectSlice      *Effect  `json:"-" msg:"-"`

	*game.DataExtend `json:"-" msg:"-"`
}

func NewProp(language *language.LanguageData, provider *game.DataProvider, prop *SettingProp) *Prop {
	extend := game.NewDataExtend(utils.ToString(prop.Id), prop.UpdateTime).Add("name", prop.Name).Add("desc", prop.Desc)
	p := &Prop{
		Id:          prop.Id,
		Name:        provider.LanguageKey(extend.Inline(), "name"),
		Desc:        provider.LanguageKey(extend.Inline(), "desc"),
		Icon:        prop.Icon,
		CanSell:     prop.CanSell,
		Mode:        prop.Mode,
		Require:     prop.Require.ReachShow(),
		Effect:      prop.EffectText.Format(language),
		Receive:     prop.Receive.TextShow(),
		SellReceive: prop.SellReceive.TextShow(),

		RequireSlice:     prop.Require.Require(),
		ReceiveSlice:     prop.Receive.Receive(),
		SellReceiveSlice: prop.SellReceive.Receive(),
		EffectSlice:      prop.Effect.Effect(),

		DataExtend: extend,
	}
	return p
}

//msgp:tuple ScienceLevel
type ScienceLevel struct {
	Level int    `json:"level" msg:"level"`
	Name  string `json:"name" msg:"name"`
	Desc  string `json:"desc" msg:"desc"`
	// 科技树升级条件
	Require CompareDataRelationReachShowSlice `json:"require" msg:"require"`
	// 科技树升级消耗
	Consume DataRelationReachShowSlice `json:"consume" msg:"consume"`
	// 科技树升级效果
	Effect ShowTextShowSlice `json:"effect" msg:"effect"`

	RequireSlice      *Require                                     `json:"-" msg:"-"`
	ConsumeSlice      *Consume                                     `json:"-" msg:"-"`
	TargetEffectSlice map[structure.PublicDataType]map[int]*Effect `json:"-" msg:"-"`

	*game.DataInlineExtend `json:"-" msg:"-"`
}

func NewScienceLevel(language *language.LanguageData, provider *game.DataProvider, parentExtend *game.DataExtend, level *SettingScienceLevel) ScienceLevel {
	extend := game.NewDataInlineExtend(utils.ToString(level.Level)).Add("name", level.Name).Add("desc", level.Name)
	parentExtend.Attach("level", extend)

	l := ScienceLevel{
		Level:   level.Level,
		Name:    provider.LanguageKey(extend, "name"),
		Desc:    provider.LanguageKey(extend, "desc"),
		Require: level.Require.ReachShow(),
		Consume: level.Consume.ReachShow(),
		Effect:  level.EffectText.Format(language),

		RequireSlice:      level.Require.Require(),
		ConsumeSlice:      level.Consume.Consume(),
		TargetEffectSlice: level.TargetEffect.Effect(),

		DataInlineExtend: extend,
	}
	return l
}

//msgp:tuple Science
type Science struct {
	Id     int            `json:"id" msg:"id"`
	Key    string         `json:"key" msg:"key"`
	Name   string         `json:"name" msg:"name"`
	Desc   string         `json:"desc" msg:"desc"`
	Icon   string         `json:"icon" msg:"icon"`
	Levels []ScienceLevel `json:"level" msg:"level"`

	*game.DataExtend `json:"-" msg:"-"`
}

func NewScience(language *language.LanguageData, provider *game.DataProvider, science *SettingScience, levels []*SettingScienceLevel) *Science {
	extend := game.NewDataExtend(utils.ToString(science.Id), science.UpdateTime).Add("name", science.Name).Add("desc", science.Desc)
	//fmt.Println("science", science, levels)
	p := &Science{
		Id:   science.Id,
		Key:  science.Key,
		Name: provider.LanguageKey(extend.Inline(), "name"),
		Desc: provider.LanguageKey(extend.Inline(), "desc"),
		Icon: science.Icon,

		DataExtend: extend,
	}
	level := make([]ScienceLevel, len(levels))
	for i := 0; i < len(level); i++ {
		l := NewScienceLevel(language, provider, extend, levels[i])
		level[i] = l
	}
	p.Levels = level
	return p
}

//msgp:tuple ShopProp
type ShopProp struct {
	Id int `json:"id" msg:"id"`
	// 购买条件
	Require CompareDataRelationReachShowSlice `json:"require" msg:"require"`
	// 购买消耗
	Consume DataRelationReachShowSlice `json:"consume" msg:"consume"`
	Prop    *Prop                      `json:"prop" msg:"prop"`

	ConsumeSlice *Consume `json:"-" msg:"-"`
	RequireSlice *Require `json:"-" msg:"-"`

	*game.DataExtend `json:"-" msg:"-"`
}

func NewShopProp(shopProp *SettingShopProp, prop *Prop) *ShopProp {
	extend := game.NewDataExtend(utils.ToString(shopProp.Id), shopProp.UpdateTime)
	p := &ShopProp{
		Id:      shopProp.Id,
		Require: shopProp.Require.ReachShow(),
		Consume: shopProp.Consume.ReachShow(),

		ConsumeSlice: shopProp.Consume.Consume(),
		RequireSlice: shopProp.Require.Require(),
		Prop:         prop,

		DataExtend: extend,
	}
	return p
}

//msgp:tuple PlayerEquip
type PlayerEquip struct {
	Id       int    `json:"id" msg:"id"`
	EquipId  int    `json:"equip_id" msg:"equip_id"`
	Level    int    `json:"level" msg:"level"`
	Location string `json:"location" msg:"location"`
	UnitId   string `json:"unit_id" msg:"unit_id"`
}

func NewPlayerEquip(userEquip *UserEquip) *PlayerEquip {
	pe := PlayerEquip{
		Id:       userEquip.Id,
		EquipId:  userEquip.EquipId,
		Level:    userEquip.Level,
		Location: userEquip.Location,
		UnitId:   userEquip.UnitId,
	}
	return &pe
}

//msgp:tuple PlayerProp
type PlayerProp struct {
	Id     int `json:"id" msg:"id"`
	PropId int `json:"prop_id" msg:"prop_id"`
	Number int `json:"number" msg:"number"`
}

func NewPlayerProp(userProp *UserProp) *PlayerProp {
	pp := &PlayerProp{
		Id:     userProp.Id,
		PropId: userProp.PropId,
		Number: userProp.Number,
	}
	return pp
}

//msgp:tuple PlayerUnit
type PlayerUnit struct {
	Id     string             `json:"id" msg:"id"`
	UnitId int                `json:"unitId" msg:"unitId"`
	Name   string             `json:"name" msg:"name"`
	Health int                `json:"health" msg:"health"`
	Index  int                `json:"index" msg:"index"`
	Level  int                `json:"level" msg:"level"`
	Status *cooperate.Sustain `json:"status" msg:"status"`
	Group  int                `json:"group" msg:"group"`
	AiMode int                `json:"ai_mode" msg:"ai_mode"`
}

func NewPlayerUnit(userUnit *UserUnit, health int, status *cooperate.Sustain, unit cooperate.PropsInstance) *PlayerUnit {
	pt := &PlayerUnit{
		Id:     utils.ToString(unit.GetId()),
		Status: status,
		AiMode: unit.ToInt(DefineAiMode),
		Health: health,
	}
	if status == nil {
		pt.Status = &cooperate.Sustain{}
	}
	if userUnit != nil {
		pt.Name = userUnit.Name
		pt.UnitId = userUnit.UnitId
		pt.Index = userUnit.Index
		pt.Level = userUnit.Level
		pt.Group = userUnit.Group
	}

	return pt
}

//msgp:tuple PlayerUnitDetail
type PlayerUnitDetail struct {
	Id     string             `json:"id" msg:"id"`
	UnitId int                `json:"unitId" msg:"unitId"`
	Name   string             `json:"name" msg:"name"`
	Index  int                `json:"index" msg:"index"`
	Level  int                `json:"level" msg:"level"`
	Title  string             `json:"title" msg:"title"`
	Equips []*EquipInUser     `json:"equips" msg:"equips"`
	Props  []*PropInUser      `json:"props" msg:"props"`
	Powers map[string]int     `json:"powers" msg:"powers"`
	Data   map[string]int     `json:"data" msg:"data"`
	Total  map[string]int32   `json:"total" msg:"total"`
	Status *cooperate.Sustain `json:"status" msg:"status"`
	Group  int                `json:"group" msg:"group"`
	AiMode int                `json:"ai_mode" msg:"ai_mode"`
}

func NewPlayerUnitDetail(userUnit *UserUnit, data map[string]int, total map[string]int32, status *cooperate.Sustain, unit cooperate.PropsInstance) *PlayerUnitDetail {
	pt := &PlayerUnitDetail{
		Id:     utils.ToString(unit.GetId()),
		Data:   data,
		Total:  total,
		Status: status,
		AiMode: unit.ToInt(DefineAiMode),
	}
	if status == nil {
		pt.Status = &cooperate.Sustain{}
	}
	if userUnit != nil {
		pt.Name = userUnit.Name
		pt.UnitId = userUnit.UnitId
		pt.Index = userUnit.Index
		pt.Level = userUnit.Level
		pt.Group = userUnit.Group

		pt.Title = userUnit.Title
		pt.Equips = userUnit.Equips
		pt.Props = userUnit.Props
		pt.Powers = utils.MapIntToString(userUnit.Powers)
	}

	return pt
}

//msgp:tuple GameUserExtend
type GameUserExtend struct {
	Title   string           `json:"title" msg:"science"`
	Science map[string]int   `json:"science" msg:"science"`
	Data    map[string]int   `json:"data" msg:"data"`
	Total   map[string]int32 `json:"total" msg:"total"`
	Props   map[string]int   `json:"props" msg:"props"`
}

func (user *GameUserExtend) BindGameUser(gameUser *user.GameUser) {
	gameUser.Extend = user
}

//msgp:tuple GameOtherUserExtend
type GameOtherUserExtend struct {
	Data     map[string]int `json:"data" msg:"data"`
	IsSystem bool           `json:"is_system" msg:"is_system"`
}

func (user *GameOtherUserExtend) BindGameUser(gameUser *user.GameOtherUser) {
	gameUser.Extend = user
}
func (user *GameOtherUserExtend) BindRankUser(rankUser *user.RankUser) {
	rankUser.Extend = user
}

//msgp:tuple MapItemInfo
type MapItemInfo struct {
	Id       interface{}              `json:"id" msg:"id"`
	DataType structure.PublicDataType `json:"data_type" msg:"data_type"`
	Data     interface{}              `json:"data" msg:"data"`
}

//msgp:tuple MapNodeInfo
type MapNodeInfo struct {
	X        int                      `json:"x" msg:"x"`
	Y        int                      `json:"y" msg:"y"`
	DataType structure.PublicDataType `json:"data_type" msg:"data_type"`
	Data     interface{}              `json:"data" msg:"data"`
}

const (
	_ user.MessageType = iota
	ShareMessage
	AchievementMessage
)

const (
	BaseAdPlane ad.AdPlane = iota
	SingleAdPlane
)

const (
	AdStat       = "ad"
	MaxLogin     = "maxlogin"
	CurrentLogin = "currentlogin"
	GoldStat     = "gold"
)

var (
	MessageTemplates = map[user.MessageType]map[string]string{
		ShareMessage: {
			"zh": "{nick_name}加入，领取分享奖励",
			"en": "",
		},
		AchievementMessage: {},
	}
)

var (
	DefaultShareReward = reward.Reward{
		Gold: 10,
	}

	AdBrandList  = []string{"unity"}
	ShowAttrList = []string{}
)

func InitConfig(config *config.SettingConfig) (interface{}, error) {
	var err error
	switch config.Key {
	case "MessageTemplates":
		err = json.Unmarshal(utils.ToBytes(config.Value), &MessageTemplates)
		return MessageTemplates, err
	case "DefaultShareReward":
		err = json.Unmarshal(utils.ToBytes(config.Value), &DefaultShareReward)
		return DefaultShareReward, err
	case "AdBrandList":
		err = json.Unmarshal(utils.ToBytes(config.Value), &AdBrandList)
		return AdBrandList, err
	case "ShowAttrList":
		err = json.Unmarshal(utils.ToBytes(config.Value), &ShowAttrList)
		return ShowAttrList, err
	case "HoldTime":
		return utils.ToInt(config.Value), nil
	case "DestroyTime":
		return utils.ToInt(config.Value), nil
	}
	return nil, errors.New("config " + config.Key + " is miss")
}
